import pyuvm
from pyuvm import *
import cocotb
from cocotb.triggers import FallingEdge, RisingEdge, Timer
from cocotb.clock import Clock
import random
# 1. 定义事务类 (Transaction)
class CounterTransaction(uvm_sequence_item):
    def __init__(self, name="CounterTransaction"):
        super().__init__(name)
        self.rst_n = 1  # 复位信号（低有效）
        self.en = 0     # 使能信号
        self.load = 0    # 加载信号
        self.load_val = 0  # 加载值
        self.count = 0   # 当前计数值
    
    def randomize_fields(self):
        """随机化事务字段"""
        self.rst_n = random.choice([0, 1])
        self.en = random.randint(0, 1)
        self.load = random.randint(0, 1) if self.en else 0
        self.load_val = random.randint(0, 15)
    
    def __str__(self):
        return (f"CounterTransaction: rst_n={self.rst_n}, en={self.en}, "
                f"load={self.load}, load_val={self.load_val}, count={self.count}")


# 3. 定义驱动程序 (Driver)
class CounterDriver(uvm_driver):
    def __init__(self, name, parent):
        super().__init__(name, parent)
        self.dut = None
    
    async def run_phase(self):
        while True:
            tr = await self.seq_item_port.get_next_item()
            await self.apply_transaction(tr)
            self.seq_item_port.item_done()
    
    async def apply_transaction(self, tr):
        if self.dut is None:
            # 获取cocotb DUT句柄
            self.dut = cocotb.top
            
        # 应用事务信号到DUT
        self.dut.rst_n.value = tr.rst_n
        self.dut.en.value = tr.en
        self.dut.load.value = tr.load
        self.dut.load_val.value = tr.load_val
        
        # 等待时钟边沿
        await RisingEdge(self.dut.clk)
        
        # 记录当前计数值（在时钟上升沿后捕获输出）
        tr.count = int(self.dut.count.value)

# 4. 定义监视器 (Monitor)
class CounterMonitor(uvm_monitor):
    def __init__(self, name, parent):
        super().__init__(name, parent)
        self.analysis_port = uvm_analysis_port("monitor_ap", self)
        self.dut = None
    
    async def run_phase(self):
        if self.dut is None:
            self.dut = cocotb.top
        
        last_count = -1
        
        while True:
            # 在时钟上升沿后捕获信号
            await RisingEdge(self.dut.clk)
            
            # 创建事务记录
            tr = CounterTransaction()
            tr.rst_n = int(self.dut.rst_n.value)
            tr.en = int(self.dut.en.value)
            tr.load = int(self.dut.load.value)
            tr.load_val = int(self.dut.load_val.value)
            tr.count = int(self.dut.count.value)
            
            # 发送到分析端口（用于计分板）
            self.analysis_port.write(tr)
            
            # 打印事务变化
            if tr.count != last_count:
                #self.logger.info(f"计数器值变化: {last_count} -> {tr.count}")
                last_count = tr.count

# 7. 定义代理 (Agent)
class CounterAgent(uvm_agent):
    def build_phase(self):
        self.driver = CounterDriver("driver", self)
        self.monitor = CounterMonitor("monitor", self)
        self.seqr = uvm_sequencer("seqr", self)
    def connect_phase(self):
        self.driver.seq_item_port.connect(self.seqr.seq_item_export)


# 8. 定义环境 (Environment)
class CounterEnv(uvm_env):
    def build_phase(self):
        super().build_phase()
        self.actual_port = uvm_blocking_get_port("monitor_ap", self)
        self.actual_fifo = uvm_tlm_analysis_fifo("actual_fifo", self)
        self.agent = CounterAgent("agent", self)
    def connect_phase(self):
        super().connect_phase()
        self.agent.monitor.analysis_port.connect(self.actual_fifo.analysis_export)
        self.actual_port.connect(self.actual_fifo.blocking_get_export)
    async def run_phase(self):
        tr = CounterTransaction()
        while True:
            # 在时钟上升沿后捕获信号
            tr = await self.actual_port.get()
            self.logger.info(f"计数器值变化: -> {tr.count}")

# 2. 定义序列类 (Sequence)
class CounterSequence(uvm_sequence):
    async def body(self):
        # 场景1: 加载值测试
        for val in [5, 10, 15]:
            tr_load = CounterTransaction()
            tr_load.en = 1
            tr_load.load = 1
            tr_load.load_val = val
            await self.start_item(tr_load)
            await self.finish_item(tr_load)
        
        # 场景2: 连续计数测试
        tr_enable = CounterTransaction()
        tr_enable.en = 1
        tr_enable.load = 0
        for _ in range(5):
            await self.start_item(tr_enable)
            await self.finish_item(tr_enable)
